﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RoardersAgentSim.Agent;

namespace RoardersAgentSim.Map
{
	/// <summary>
	/// Implementation of the FULL MAP (mostly useful for 
	/// </summary>
	public class FullMap
	{
		#region private fields
		/// <summary>
		/// 
		/// </summary>
		public List<Node> Nodes{get; private set;}
		/// <summary>
		/// 
		/// </summary>
		public List<Zone> Zones { get; private set; }
		/// <summary>
		/// The full list of car roadlinks
		/// </summary>
		public List<RoadLink> CarRoadLinks { get; private set; }
		/// <summary>
		/// The full list of walking road links
		/// </summary>
		public List<RoadLink> WalkRoadLinks { get; private set; }
		#endregion
		#region public properties
		/// <summary>
		/// Check if the map was initialised
		/// </summary>
		public bool Initialised { get; private set; }
		#endregion
		#region initialiser
		/// <summary>
		/// initialise the map from the selected map directory
		/// </summary>
		/// <param name="mapDirectoryPath"></param>
        public void Initialise(CSVUtils.Initializer init)
        {
            if (!Initialised)
            {
                //fake initialisation with the demo graph
                Nodes = new List<Node>();
                Zones = new List<Zone>();
                this.CarRoadLinks = new List<RoadLink>();
                this.WalkRoadLinks = new List<RoadLink>();
                List<CSVUtils.CSVMapping.ZoneMapping> zones = init.ParseZones();
                List<CSVUtils.CSVMapping.NodeMapping> nodes = init.ParseNodes();
                List<CSVUtils.CSVMapping.LinkMapping> links = init.ParseLinks();
                InitZones(zones);
                InitNodeAndLinks(nodes, links);
                Initialised = true;
            }
        }

		/// <summary>
		/// initialise the nodes on the map
		/// </summary>
		/// <param name="nodes"></param>
		/// <param name="links"></param>
		private void InitNodeAndLinks(List<CSVUtils.CSVMapping.NodeMapping> nodes, List<CSVUtils.CSVMapping.LinkMapping> links)
		{
			foreach (CSVUtils.CSVMapping.NodeMapping nodeMapping in nodes)
			{
				Zone z = this.Zones.FirstOrDefault(x => x.ZoneID == nodeMapping.ZoneID);
				if (z == null)
					throw new Exception("Unrecognized zone " + nodeMapping.ZoneID);
				Node n = new Node(nodeMapping,z);
				Nodes.Add(n);
			}



			foreach (CSVUtils.CSVMapping.LinkMapping linkMapping in links)
			{
				RoadLink rl = new RoadLink(linkMapping);
				Node destinationNode = this.Nodes.FirstOrDefault(x => x.NodeID == linkMapping.DestinationNode);
				if (destinationNode == null)
					throw new Exception("Unrecognized destination node for link " + rl.Link.LinkID);
				Node sourceNode = this.Nodes.FirstOrDefault(x => x.NodeID == linkMapping.SourceNode);
				if (sourceNode == null)
					throw new Exception("Unrecognized source node for link " + rl.Link.LinkID);
				Zone z = sourceNode.Zone;
				if (sourceNode.Zone.ZoneID != destinationNode.Zone.ZoneID)
				{
					switch (linkMapping.CompromiseZone.ToUpper().Trim())
					{
						case "SOURCE":
							break;
						case "DESTINATION":
							z = destinationNode.Zone;
							break;
						default:
							break;
					}
				}
				rl.SetZone(z);
				switch (rl.Link.Type)
				{
					case LinkType.CAR_LINK:
						sourceNode.AddOutGoingCarLink(rl);
						destinationNode.AddInGoingCarLink(rl);
						this.CarRoadLinks.Add(rl);
						break;
					case LinkType.WALK_LINK:
						sourceNode.AddOutGoingWalkLink(rl);
						destinationNode.AddInGoingWalkLink(rl);
						this.WalkRoadLinks.Add(rl);
						break;
					default:
						break;
				}
				
			}

		}
		/// <summary>
		/// Initialise the zones on the map;
		/// </summary>
		/// <param name="zones"></param>
		private void InitZones(List<CSVUtils.CSVMapping.ZoneMapping> zones)
		{
			foreach(CSVUtils.CSVMapping.ZoneMapping mapping in zones)
			{
				Zone z = new Zone(mapping);
				this.Zones.Add(z);
			}
		}
		#endregion

        internal Node GetNode(string nodeId)
        {
            return Nodes.FirstOrDefault(x => x.NodeID == nodeId);
        }
    }
}
